// Copyright 2007 Google, Inc. All Rights Reserved.

package com.google.jessewilson.codesearch.commandlinesearch;

import com.google.jessewilson.codesearch.api.SearchProvider;
import com.google.jessewilson.codesearch.configuration.SearchProviderConfiguration;
import com.google.jessewilson.codesearch.io.jdom.EasyElement;
import com.google.jessewilson.codesearch.io.jdom.Externalizer;
import com.google.jessewilson.codesearch.util.Preconditions;
import org.jdom.Element;

/**
 * Configure a command line code search.
 *
 * @author jessewilson
 */
public final class ClsConfiguration implements SearchProviderConfiguration {

  private final String executable;
  private final String arguments;
  private final String parseLineRegex;
  private final int filePathMatch;
  private final int lineNumberMatch;
  private final int lineValueMatch;
  private boolean convertToRegex;

  private ClsConfiguration(Builder builder) {
    this.executable = builder.executable;
    this.arguments = builder.arguments;
    this.parseLineRegex = builder.parseLineRegex;
    this.filePathMatch = builder.filePathMatch;
    this.lineNumberMatch = builder.lineNumberMatch;
    this.lineValueMatch = builder.lineValueMatch;
    this.convertToRegex = builder.convertToRegex;
  }

  /**
   * The path to the executable, such as {@code /bin/codesearch}.
   */
  public String getExecutable() {
    return executable;
  }

  /**
   * A series of space separated arguments to the executable.
   */
  public String getArguments() {
    return arguments;
  }

  /**
   * A regular expression that will split up each line of the search results
   * into is component parts: the line number, path and line text.
   */
  public String getParseLineRegex() {
    return Preconditions.checkNotNull(parseLineRegex);
  }

  /**
   * The match index of the file path from the parsed regular expression.
   */
  public int getFilePathMatch() {
    return filePathMatch;
  }

  /**
   * The match index of the line number from the parsed regular expression.
   */
  public int getLineNumberMatch() {
    return lineNumberMatch;
  }

  /**
   * The match index of the line value from the parsed regular expression.
   */
  public int getLineValueMatch() {
    return lineValueMatch;
  }

  /**
   * Whether to convert the search terms into regular expressions by
   * escaping special characters.
   *
   * @see com.google.jessewilson.codesearch.util.StringToRegex
   */
  public boolean getConvertToRegex() {
    return convertToRegex;
  }

  public SearchProvider getSearchProvider() {
    return new ClsSearchProvider();
  }

  public static class Builder {
    private String executable;
    private String arguments;
    private String parseLineRegex;
    private int filePathMatch;
    private int lineNumberMatch;
    private int lineValueMatch;
    private boolean convertToRegex;

    public Builder executable(String executable) {
      this.executable = executable;
      return this;
    }

    public Builder arguments(String arguments) {
      this.arguments = arguments;
      return this;
    }

    public Builder parseLineRegex(String parseLineRegex) {
      this.parseLineRegex = parseLineRegex;
      return this;
    }

    public Builder filePathMatch(int filePathMatch) {
      this.filePathMatch = filePathMatch;
      return this;
    }

    public Builder lineNumberMatch(int lineNumberMatch) {
      this.lineNumberMatch = lineNumberMatch;
      return this;
    }

    public Builder lineValueMatch(int lineValueMatch) {
      this.lineValueMatch = lineValueMatch;
      return this;
    }

    public Builder convertToRegex(boolean convertToRegex) {
      this.convertToRegex = convertToRegex;
      return this;
    }

    public ClsConfiguration build() {
      return new ClsConfiguration(this);
    }
  }

  public static class MyExternalizer implements Externalizer<ClsConfiguration> {
    private static final String EXECUTABLE = "executable";
    private static final String ARGUMENTS = "arguments";
    private static final String PARSE_LINE_REGEX = "parseLineRegex";
    private static final String FILE_PATH_MATCH = "filePathMatch";
    private static final String LINE_NUMBER_MATCH = "lineNumberMatch";
    private static final String LINE_VALUE_MATCH = "lineValueMatch";
    private static final String CONVERT_TO_REGEX = "convertToRegex";

    public void writeExternal(Element target, ClsConfiguration data) {
      EasyElement easyElement = new EasyElement(target);
      easyElement.putString(EXECUTABLE, data.executable);
      easyElement.putString(ARGUMENTS, data.arguments);
      easyElement.putString(PARSE_LINE_REGEX, data.parseLineRegex);
      easyElement.putInt(FILE_PATH_MATCH, data.filePathMatch);
      easyElement.putInt(LINE_NUMBER_MATCH, data.lineNumberMatch);
      easyElement.putInt(LINE_VALUE_MATCH, data.lineValueMatch);
      easyElement.putBoolean(CONVERT_TO_REGEX, data.convertToRegex);
    }

    public ClsConfiguration readExternal(Element source) {
      EasyElement easyElement = new EasyElement(source);

      return new ClsConfiguration.Builder()
          .executable(easyElement.getString(EXECUTABLE, null))
          .arguments(easyElement.getString(ARGUMENTS, null))
          .parseLineRegex(easyElement.getString(PARSE_LINE_REGEX, null))
          .filePathMatch(easyElement.getInt(FILE_PATH_MATCH, 0))
          .lineNumberMatch(easyElement.getInt(LINE_NUMBER_MATCH, 0))
          .lineValueMatch(easyElement.getInt(LINE_VALUE_MATCH, 0))
          .convertToRegex(easyElement.getBoolean(CONVERT_TO_REGEX, false))
          .build();
    }
  }
}
